/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "accessibility_screen_reader_service.h"
#include "accessible_ability_manager_service.h"
#include "accessibility_window_manager.h"
#include "accessibility_espeak_proxy.h"
#include "accessibility_espeak_player.h"
#include "accessibility_common_event.h"

#include "utils.h"

#include <vector>
#include <string>




namespace OHOS {
namespace Accessibility {
namespace {
    MMI::InputManager* inputManager_ = MMI::InputManager::GetInstance();
    std::map<int32_t, std::pair<bool, std::pair<int32_t, int32_t>>> accessibleKeyCodeTable = {
        {ActionType::ACCESSIBILITY_ACTION_HOME,
            {true, {MMI::KeyEvent::KEYCODE_HOME, MMI::KeyEvent::KEYCODE_HOME}}}, // 1
        {ActionType::ACCESSIBILITY_ACTION_BACK,
            {true, {MMI::KeyEvent::KEYCODE_BACK, MMI::KeyEvent::KEYCODE_BACK}}}, // 2
        {ActionType::ACCESSIBILITY_ACTION_RECENTTASK,
            {true, {MMI::KeyEvent::KEYCODE_VIRTUAL_MULTITASK, MMI::KeyEvent::KEYCODE_VIRTUAL_MULTITASK}}}, // 2210
        {ActionType::ACCESSIBILITY_ACTION_RECENTTASK1,
            {true, {MMI::KeyEvent::KEYCODE_MENU, MMI::KeyEvent::KEYCODE_MENU}}}, // 2067
        {ActionType::ACCESSIBILITY_ACTION_RECENTTASK2,
            {true, {MMI::KeyEvent::KEYCODE_TASKMANAGER, MMI::KeyEvent::KEYCODE_TASKMANAGER}}}, // 2717
        {ActionType::ACCESSIBILITY_ACTION_RECENTTASK3,
            {true, {MMI::KeyEvent::KEYCODE_APPSELECT, MMI::KeyEvent::KEYCODE_APPSELECT}}}, // 2720
        {ActionType::ACCESSIBILITY_ACTION_CAMERA,
            {true, {MMI::KeyEvent::KEYCODE_CAMERA, MMI::KeyEvent::KEYCODE_CAMERA}}}, // 19
        {ActionType::ACCESSIBILITY_ACTION_COPY,
            {true, {MMI::KeyEvent::KEYCODE_COPY, MMI::KeyEvent::KEYCODE_COPY}}}, // 2620
        {ActionType::ACCESSIBILITY_ACTION_PASTE,
            {true, {MMI::KeyEvent::KEYCODE_PASTE, MMI::KeyEvent::KEYCODE_PASTE}}}, // 2622
        {ActionType::ACCESSIBILITY_ACTION_CUT,
            {true, {MMI::KeyEvent::KEYCODE_CUT, MMI::KeyEvent::KEYCODE_CUT}}}, // 2624
        {ActionType::ACCESSIBILITY_ACTION_CALL,
            {true, {MMI::KeyEvent::KEYCODE_CALL, MMI::KeyEvent::KEYCODE_CALL}}}, // 3
        {ActionType::ACCESSIBILITY_ACTION_MUTE,
            {true, {MMI::KeyEvent::KEYCODE_MUTE, MMI::KeyEvent::KEYCODE_MUTE}}} // 23
    }; // 23
} // namespace

ScreenReader::ScreenReader()
{
    
}

ScreenReader::~ScreenReader()
{
    
}

bool ScreenReader::OnStart()
{
    HILOG_DEBUG("ScreenReader OnStart");
    if(!Singleton<EspeakPlayer>::GetInstance().Init()){
        HILOG_DEBUG("EspeakPlayer init failed");
        return false;
    }
    EspeakProxy::Init();
    EspeakProxy::Synthesize("屏幕朗读已开启");
    isScreenReaderEnabled_ = true;
    HILOG_DEBUG("ScreenReader OnStart end");
    return true;
}

bool ScreenReader::OnStop()
{
    HILOG_DEBUG("ScreenReader OnStop");
    EspeakProxy::Synthesize("屏幕朗读已关闭");
    EspeakProxy::Release();
    Singleton<EspeakPlayer>::GetInstance().Release();
    isScreenReaderEnabled_ = false;
    HILOG_DEBUG("ScreenReader OnStop end");
    return true;
}

void ScreenReader::OnAccessibilityEvent(const AccessibilityEventInfo &uiEvent)
{
    if(!isScreenReaderEnabled_){
        HILOG_DEBUG("ScreenReader is not enabled");
        return;
    }
    HILOG_DEBUG("eventType[0x%{public}x]",uiEvent.GetEventType());
    EventType eventType=uiEvent.GetEventType();
    int64_t start_event_time = Utils::GetSystemTime();
    int64_t end_event_time = 0;
    if(eventType==EventType::TYPE_GESTURE_EVENT){
        HILOG_DEBUG("gesture event");
        gestureEventHandler_.OnGestureEvent(uiEvent);
        end_event_time = Utils::GetSystemTime();
        HILOG_DEBUG(PERFORMANCE_TEST "gesture event cost time: %{public}lld ms", end_event_time - start_event_time);
    }else{
        HILOG_DEBUG("accessibility event");
        accessibilityEventHandler_.OnAccessibilityEvent(uiEvent);
        end_event_time = Utils::GetSystemTime();
        HILOG_DEBUG(PERFORMANCE_TEST "accessibility event cost time: %{public}lld ms", end_event_time - start_event_time);
    }
}

void ScreenReader::OnCommonEvent(const int32_t eventType)
{
    HILOG_DEBUG("COMMON_EVENT_SCREEN commonEvent: %{public}d", eventType);
    if(!isScreenReaderEnabled_){
        HILOG_DEBUG("ScreenReader is not enabled");
        return;
    }
    switch (eventType) {
        case ScreenReaderCommonEvent::COMMON_EVENT_SCREEN_ON:{
            HILOG_DEBUG("COMMON_EVENT_SCREEN_ON");

            //获取系统时间
            int32_t year, month, day, hour, minute;
            Utils::GetCurrentDateTime(&minute, &hour, &day, &month, &year);

            //获取系统电量
            int32_t bc=Singleton<AccessibleAbilityManagerService>::GetInstance().GetBatteryCapacity();
            HILOG_DEBUG("COMMON_EVENT_SCREEN year:%{public}d, month:%{public}d, day:%{public}d, hour:%{public}d, minute:%{public}d, bc:%{public}d", year, month, day, hour, minute, bc);

            char buf[128];
            sprintf(buf, "屏幕已打开，当前时间：%d年%d月%d日%d点%d分，剩余电量：百分之%d", year, month, day, hour, minute, bc);
            EspeakProxy::Synthesize(buf);
            break;
        }
        case ScreenReaderCommonEvent::COMMON_EVENT_SCREEN_OFF:
            HILOG_DEBUG("COMMON_EVENT_SCREEN_OFF");
            EspeakProxy::Synthesize("屏幕已关闭。");
            break;
        default:
            HILOG_DEBUG("COMMON_EVENT_SCREEN default");
            break;
    }
}

void ScreenReader::HilogElementInfo(const AccessibilityElementInfo &elementInfo)
{
    HILOG_DEBUG("CONTENT_TAG");
    int64_t elementId=elementInfo.GetAccessibilityId();
    const std::string &text=elementInfo.GetContent();
    const std::string &hintText=elementInfo.GetHint();
    const std::string &accibilityText=elementInfo.GetAccessibilityText();
    const std::string &contentDescription=elementInfo.GetDescriptionInfo();
    bool accessibilityFocused=elementInfo.HasAccessibilityFocus();
    bool hint=elementInfo.IsGivingHint();
    int64_t parentId=elementInfo.GetParentNodeId();
    int32_t childCount=elementInfo.GetChildCount();
    const std::vector<int64_t> &childIds=elementInfo.GetChildIds();
    int32_t currentIndex=elementInfo.GetCurrentIndex();
    int32_t leftTopX = elementInfo.GetRectInScreen().GetLeftTopXScreenPostion();
    int32_t leftTopY = elementInfo.GetRectInScreen().GetLeftTopYScreenPostion();
    int32_t rightBottomX = elementInfo.GetRectInScreen().GetRightBottomXScreenPostion();
    int32_t rightBottomY = elementInfo.GetRectInScreen().GetRightBottomYScreenPostion();
    int32_t newDisplayX = (leftTopX + rightBottomX) / 2;
    int32_t newDisplayY = (leftTopY + rightBottomY) / 2;
    HILOG_DEBUG("CONTENT_TAG STARTING TO LOG ELEMENT INFO...");
    HILOG_DEBUG("CONTENT_TAG centerX[%{public}d] centerY[%{public}d]", newDisplayX, newDisplayY);
    HILOG_DEBUG("CONTENT_TAG elementId[%{public}" PRId64 "]", elementId);
    HILOG_DEBUG("CONTENT_TAG text[%{public}s]", text.c_str());
    HILOG_DEBUG("CONTENT_TAG hintText[%{public}s]", hintText.c_str());
    HILOG_DEBUG("CONTENT_TAG accibilityText[%{public}s]", accibilityText.c_str());
    HILOG_DEBUG("CONTENT_TAG contentDescription[%{public}s]", contentDescription.c_str());
    HILOG_DEBUG("CONTENT_TAG componentType[%{public}s]", elementInfo.GetComponentType().c_str());
    HILOG_DEBUG("CONTENT_TAG clickable[%{public}d]", elementInfo.IsClickable());
    HILOG_DEBUG("CONTENT_TAG focusable[%{public}d]", elementInfo.IsFocusable());
    HILOG_DEBUG("CONTENT_TAG accessibilityFocused[%{public}d]", accessibilityFocused);
    HILOG_DEBUG("CONTENT_TAG hint[%{public}d]", hint);
    HILOG_DEBUG("CONTENT_TAG parentId[%{public}" PRId64 "]", parentId);
    HILOG_DEBUG("CONTENT_TAG childCount[%{public}d]", childCount);
    HILOG_DEBUG("CONTENT_TAG currentIndex[%{public}d]", currentIndex);
    int realChildCount = childIds.size();
    for (int i = 0; i < realChildCount; i++)
    {
        HILOG_DEBUG("CONTENT_TAG childId[%{public}" PRId64 "]", childIds[i]);
    }
    HILOG_DEBUG("CONTENT_TAG ENDING TO LOG ELEMENT INFO...");
}

AccessibilityElementInfo ScreenReader::FindParentElementInfo(const AccessibilityElementInfo &elementInfo)
{
    HILOG_DEBUG();
    int64_t start_time = Utils::GetSystemTime();
    int64_t parentId=elementInfo.GetParentNodeId();
    //int32_t parentWindowId=elementInfo.GetParentWindowId();
    int32_t parentWindowId=elementInfo.GetWindowId();
    HILOG_DEBUG("parentId[%{public}" PRId64 "] parentWindowId[%{public}d]", parentId, parentWindowId);
    AccessibilityElementInfo parentElementInfo = {};
    Singleton<AccessibleAbilityManagerService>::GetInstance().FindElementInfoByAccessibilityId(parentId, parentWindowId, parentElementInfo);
    int64_t end_time = Utils::GetSystemTime();
    HILOG_DEBUG(PERFORMANCE_TEST "FindParentElementInfo cost time: %{public}lld ms", end_time - start_time);
    return parentElementInfo;
}

AccessibilityElementInfo ScreenReader::FindFocusableParentElement(const AccessibilityElementInfo &elementInfo)
{
    HILOG_DEBUG();
    AccessibilityElementInfo parentElementInfo = FindParentElementInfo(elementInfo);
    while (!parentElementInfo.IsFocusable()){
        HILOG_DEBUG("parentElement id %{public}lld is not focusable", parentElementInfo.GetAccessibilityId());
        parentElementInfo = FindParentElementInfo(parentElementInfo);
    }
    HILOG_DEBUG("parentElement id %{public}lld is focusable", parentElementInfo.GetAccessibilityId());
    return parentElementInfo;
    
}

void ScreenReader::SetKeyCodeToMmi(std::shared_ptr<MMI::KeyEvent>& keyEvent, const bool isPress,
    const int32_t keyCode)
{
    HILOG_DEBUG();
    Singleton<AccessibleAbilityManagerService>::GetInstance().PostDelayUnloadTask();
    if (keyEvent == nullptr) {
        HILOG_ERROR("KeyEvent is nullptr");
        return;
    }
    MMI::KeyEvent::KeyItem item;
    item.SetPressed(isPress);
    item.SetKeyCode(keyCode);
    keyEvent->AddKeyItem(item);
    keyEvent->SetKeyCode(keyCode);
}

bool ScreenReader::TransmitActionToMmi(const int32_t action)
{
    HILOG_DEBUG("The action is %{public}d", action);
    Singleton<AccessibleAbilityManagerService>::GetInstance().PostDelayUnloadTask();
    std::shared_ptr<MMI::KeyEvent> keyEventUp = MMI::KeyEvent::Create();
    std::shared_ptr<MMI::KeyEvent> keyEventDown = MMI::KeyEvent::Create();
    if (keyEventUp == nullptr || keyEventDown == nullptr) {
        HILOG_ERROR("KeyEvent is nullptr");
        return false;
    }

    if (!inputManager_) {
        HILOG_ERROR("inputManager_ is nullptr");
        return false;
    }
    
    HILOG_INFO("Transmit keycode to MMI");

    // true的话，只add一个first，false的话，add两个：first和second
    if (accessibleKeyCodeTable.at(action).first) {
        SetKeyCodeToMmi(keyEventDown, true, accessibleKeyCodeTable.at(action).second.first);
        SetKeyCodeToMmi(keyEventUp, false, accessibleKeyCodeTable.at(action).second.first);
    } else {
        SetKeyCodeToMmi(keyEventDown, true, accessibleKeyCodeTable.at(action).second.first);
        SetKeyCodeToMmi(keyEventUp, false, accessibleKeyCodeTable.at(action).second.first);
        SetKeyCodeToMmi(keyEventDown, true, accessibleKeyCodeTable.at(action).second.second);
    }
    keyEventDown->SetKeyAction(MMI::KeyEvent::KEY_ACTION_DOWN);
    keyEventUp->SetKeyAction(MMI::KeyEvent::KEY_ACTION_UP);
    inputManager_->SimulateInputEvent(keyEventDown);
    inputManager_->SimulateInputEvent(keyEventUp);

    return true;
}

bool ScreenReader::ExecuteAction(const ActionType action)
{
    HILOG_DEBUG("actionType[%{public}d]", action);
    if(accessibleKeyCodeTable.find(action) != accessibleKeyCodeTable.end()) {
        if(!TransmitActionToMmi(action)) {
            HILOG_ERROR("TransmitActionToMmi failed");
            return false;
        }
        return true;
    }
    HILOG_ERROR("actionType[%{public}d] not found, need check", action);
    return false;
}

void ScreenReader::InsertCache(const int32_t windowId, const int32_t pageId, const int64_t elementId)
{
    HILOG_DEBUG("windowId[%{public}d], pageId[%{public}d], elementId[%{public}" PRId64 "]", windowId, pageId, elementId);
    if(windowId==AccessibilityElementInfo::UNDEFINED_WINID_ID || elementId==AccessibilityElementInfo::UNDEFINED_ACCESSIBILITY_ID){
        HILOG_DEBUG("invalid windowId or elementId");
        return;
    }
    int64_t cacheKey=(int64_t) windowId << 32 | (int64_t) pageId;
    pageFocusedElementCache_[cacheKey] = elementId;
}

int64_t ScreenReader::GetCacheElementId(const int32_t windowId, const int32_t pageId)
{
    HILOG_DEBUG("windowId[%{public}d], pageId[%{public}d]", windowId, pageId);
    int64_t cacheKey=(int64_t) windowId << 32 | (int64_t) pageId;
    if (pageFocusedElementCache_.find(cacheKey) != pageFocusedElementCache_.end()) {
        return pageFocusedElementCache_[cacheKey];
    }
    HILOG_DEBUG("no cache elementId in this page");
    return AccessibilityElementInfo::UNDEFINED_ACCESSIBILITY_ID;
}

bool ScreenReader::FindRootElement(AccessibilityElementInfo &rootElementInfo)
{
    HILOG_DEBUG();
    int64_t start_time = Utils::GetSystemTime();
    auto &aams=Singleton<AccessibleAbilityManagerService>::GetInstance();
    auto& awm = Singleton<AccessibilityWindowManager>::GetInstance();
    int32_t activeWindowId=awm.activeWindowId_;
    int64_t rootElementId=awm.GetSceneBoardElementId(activeWindowId, -1); // -1 means root element
    bool ret = aams.FindElementInfoByAccessibilityId(rootElementId, activeWindowId, rootElementInfo);
    int64_t end_time = Utils::GetSystemTime();
    HILOG_DEBUG(PERFORMANCE_TEST "FindRootElement cost time: %{public}lld ms", end_time - start_time);
    if(!ret) {
        HILOG_ERROR("FindRootElement failed");
    }
    return ret;
}

bool ScreenReader::FindFirstElement(AccessibilityElementInfo &firstElement)
{
    HILOG_DEBUG();
    int64_t start_time = Utils::GetSystemTime();
    auto &aams=Singleton<AccessibleAbilityManagerService>::GetInstance();
    // find root element
    AccessibilityElementInfo rootElement={};
    if(!FindRootElement(rootElement)){
        HILOG_ERROR("FindRootElement failed");
        return false;
    }
    // first child of root element
    int32_t windowId=rootElement.GetWindowId();
    int64_t firstChildId=rootElement.GetChildId(0);
    HILOG_DEBUG("rootElementId[%{public}" PRId64"], firstChildId[%{public}" PRId64 "]", rootElement.GetAccessibilityId(), firstChildId);
    // print log element info
    // HilogElementInfo(rootElement);

    //find first focusable element
    int64_t firstId=firstChildId;
    std::string s;
    do{
        aams.FindElementInfoByAccessibilityId(firstId, windowId, firstElement);
        s=firstElement.GetComponentType();
        firstId=firstElement.GetChildId(0);
    }while(!CheckFocusable(firstElement) && firstId != -1);
    int64_t end_time = Utils::GetSystemTime();
    HILOG_DEBUG(PERFORMANCE_TEST "FindFirstElement cost time: %{public}lld ms", end_time - start_time);
    // HilogElementInfo(firstElement);
    // 第一个child不一定是页面第一个可聚焦元素
    if(CheckFocusable(firstElement)){
        HILOG_DEBUG("find first focusable element");
        return true;
    }
    return false;
}

bool ScreenReader::CheckFocusable(const AccessibilityElementInfo &elementInfo)
{
    // std::string s=elementInfo.GetComponentType();
    // if(elementInfo.GetWindowId()==2) return true;
    // if(s=="Row"||s=="Badge") return true;
    // if(!elementInfo.IsClickable()|| s=="Column" ||s == "Dialog" || s == "Swiper" || s == "Stack" || s == "SwiperIndicator"){
    //     HILOG_DEBUG("false");
    //     return false;
    // }
    // return true;
    if(!elementInfo.IsFocusable()) return false;
    if(!elementInfo.IsClickable() && !elementInfo.IsLongClickable()) return false;
    if(!elementInfo.IsVisible()) return false;
    return true;
}

bool ScreenReader::DrawFocus(const AccessibilityElementInfo &elementInfo, const int32_t flag)
{
    HILOG_DEBUG("DrawFocus");
    int64_t start_time = Utils::GetSystemTime();
    int64_t end_time;
    int32_t windowId=elementInfo.GetWindowId();
    int32_t pageId=elementInfo.GetPageId();
    int64_t elementId=elementInfo.GetAccessibilityId();
    HILOG_DEBUG("windowId[%{public}d], pageId[%{public}d], elementId[%{public}" PRId64 "], flag[%{public}d]", windowId, pageId, elementId, flag);
    auto &aams=Singleton<AccessibleAbilityManagerService>::GetInstance();
    if(aams.GetFocusElementId() != AccessibilityElementInfo::UNDEFINED_ACCESSIBILITY_ID){
        aams.ExecuteActionOnAccessibilityFocused(ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS);
    }
    // regardless of whether flag is 0 or not, check if the element is focusable
    if(CheckFocusable(elementInfo)){
        HILOG_DEBUG("flag=0 or focusable");
        aams.SetFocusWindowId(windowId);
        aams.SetFocusElementId(elementId);
        aams.ExecuteActionOnAccessibilityFocused(ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS);
        InsertCache(windowId, pageId, elementId);
        // get content
        // HILOG_DEBUG("content[%{public}s]",GetContent(elementInfo).c_str());
        EspeakProxy::Synthesize(GetContent(elementInfo).c_str());
        end_time = Utils::GetSystemTime();
        HILOG_DEBUG(PERFORMANCE_TEST "Drawfocus cost time: %{public}lld ms", end_time - start_time);
        return true;
    }
    // if(flag==0){
    //     HILOG_DEBUG("flag=0, not focusable");
    //     return false;
    // }

    AccessibilityElementInfo child={};
    int64_t childId;
    if(flag==-1){
        // -1, first focusable child
        childId=elementInfo.GetChildId(0);
        aams.FindElementInfoByAccessibilityId(childId, windowId, child);
        while(!CheckFocusable(child)&&child.GetChildCount()>0){
            childId=child.GetChildId(0);
            aams.FindElementInfoByAccessibilityId(childId, windowId, child);
        }
    }else if(flag==1){
        // 1, last focusable child
        childId=elementInfo.GetChildId(elementInfo.GetChildCount()-1);
        aams.FindElementInfoByAccessibilityId(childId, windowId, child);
        while(!CheckFocusable(child)&&child.GetChildCount()>0){
            childId=child.GetChildId(child.GetChildCount()-1);
            aams.FindElementInfoByAccessibilityId(childId, windowId, child);
        }
    }
    // focus
    if(CheckFocusable(child)){
        HILOG_DEBUG("flag = 1 or -1, focus child");
        aams.SetFocusWindowId(child.GetWindowId());
        aams.SetFocusElementId(child.GetAccessibilityId());
        aams.ExecuteActionOnAccessibilityFocused(ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS);
        InsertCache(child.GetWindowId(), child.GetPageId(), child.GetAccessibilityId());
        // get content
        //HILOG_DEBUG("content[%{public}s]",GetContent(child).c_str());
        EspeakProxy::Synthesize(GetContent(elementInfo).c_str());
        end_time = Utils::GetSystemTime();
        HILOG_DEBUG(PERFORMANCE_TEST "Drawfocus cost time: %{public}lld ms", end_time - start_time);
        return true;
    }
    // 聚焦失败
    aams.SetFocusWindowId(AccessibilityElementInfo::UNDEFINED_ACCESSIBILITY_ID);
    aams.SetFocusElementId(AccessibilityElementInfo::UNDEFINED_ACCESSIBILITY_ID);
    end_time = Utils::GetSystemTime();
    HILOG_DEBUG(PERFORMANCE_TEST "Drawfocus cost time: %{public}lld ms", end_time - start_time);
    HILOG_DEBUG("draw focus on current element failed");
    return false;
}

const std::string ScreenReader::GetContent(const AccessibilityElementInfo &elementInfo)
{
    HILOG_DEBUG("windowId[%{public}d], elementId[%{public}" PRId64 "]", elementInfo.GetWindowId(), elementInfo.GetAccessibilityId());
    int64_t start_time = Utils::GetSystemTime();
    std::string content = ""; // content to return
    // dfs获取当前element所有文本内容
    if(elementInfo.GetComponentType()=="Text"){
        HILOG_DEBUG("content: %{public}s", elementInfo.GetContent().c_str());
        content.append(elementInfo.GetContent());
        content.append(",");
    }
    if(elementInfo.GetChildCount()==0){
        HILOG_DEBUG("no child");
        return content;
    }
    int32_t windowId=elementInfo.GetWindowId();
    const std::vector<int64_t> childIds = elementInfo.GetChildIds();
    AccessibilityElementInfo curChildElement={}; // current child element
    auto &aams=Singleton<AccessibleAbilityManagerService>::GetInstance();
    // dfs to find text type child
    for(int64_t childId:childIds){
        aams.FindElementInfoByAccessibilityId(childId, windowId, curChildElement);
        content.append(GetContent(curChildElement));
    }
    int64_t end_time = Utils::GetSystemTime();
    HILOG_DEBUG(PERFORMANCE_TEST "GetContent cost time: %{public}lld ms", end_time - start_time);
    HILOG_DEBUG("content: %{public}s", content.c_str());
    return content;
}

void ScreenReader::SpeakFullScreen()
{
    HILOG_DEBUG("SpeakFullScreen");
    int64_t start_time = Utils::GetSystemTime();
    // 查找根节点，直接深搜根节点信息
    AccessibilityElementInfo rootElement={};
    FindRootElement(rootElement);
    std::string screenContent = "开始朗读屏幕内容：";
    screenContent.append(GetContent(rootElement));
    int64_t end_time = Utils::GetSystemTime();
    HILOG_DEBUG(PERFORMANCE_TEST "find full screen content cost time: %{public}lld ms", end_time - start_time);
    HILOG_DEBUG("screenContent: %{public}s", screenContent.c_str());
    EspeakProxy::Synthesize(screenContent.c_str());
    end_time = Utils::GetSystemTime();
    HILOG_DEBUG(PERFORMANCE_TEST "SpeakFullScreen cost time: %{public}lld ms", end_time - start_time);
}

} // namespace Accessibility
} // namespace OHOS